#pragma once

#include <stddef.h>
#include "SpinLock.h"
#include "BufList.h"
#include "Buffer.h"
#include "BufBlock.h"
#include "BufBlockMgr.h"
#include "BufChunkMgr.h"

template <typename CLock = CFakeLock>
class CBufMgr
{
    typedef CBufList<BufBlock, CLock> CBlockList;
    typedef typename CBlockList::ListNode BlockNode;
    typedef CBufList<CBuffer<CLock>, CLock> CBufLst;
    typedef typename CBufLst::ListNode BufNode;

public:
    CBufMgr()
    {
        m_pChunks = nullptr;
        m_pBlocks = nullptr;
        m_bIntAlloc = false;
    }

    ~CBufMgr() { Destroy(); }

    void *operator new(size_t, void *ptr) _GLIBCXX_USE_NOEXCEPT { return ptr; }
    void operator delete(void *ptr) {}

public:
    static CBufMgr<CLock> *Create(void *pChunk, uint64_t nSize)
    {
        uint64_t nLen = 0;
        void *ptr = nullptr;
        bool bIntAlloc = false;
        CBufMgr<CLock> *pMgr = nullptr;

        if (nullptr == pChunk)
        {
            pChunk = malloc(nSize);
            bIntAlloc = true;
        }

        if (nullptr == pChunk)
            return nullptr;

        // 内存块头为CBufMgr实例
        pMgr = new (pChunk) CBufMgr<CLock>();
        pMgr->m_bIntAlloc = bIntAlloc;
        nLen = nSize - sizeof(CBufMgr<CLock>);

        // CBufMgr实例后为CBufChunkMgr实例
        ptr = (char *)pMgr + sizeof(CBufMgr<CLock>);
        pMgr->m_pChunks = new (ptr) CBufChunkMgr<CLock>();

        // CBufChunkMgr实例后为Chunk可分配内存
        nLen -= sizeof(CBufChunkMgr<CLock>);
        ptr = (char *)ptr + sizeof(CBufChunkMgr<CLock>);
        pMgr->m_pChunks->Init(ptr, nLen);

        return pMgr;
    }

    bool Init()
    {
        void *ptr = nullptr;

        if (nullptr == m_pChunks)
            return false;

        m_lstBuffer.SetChunkMgr(m_pChunks);
        ptr = m_pChunks->Alloc(sizeof(CBufBlockMgr<CLock>));

        if (nullptr == ptr)
            return false;

        // 创建块管理实例
        m_pBlocks = new (ptr) CBufBlockMgr<CLock>(m_pChunks);

        return true;
    }

    void Destroy()
    {
        if (0 < m_lstBuffer.GetSize())
            m_lstBuffer.Destroy();

        if (nullptr != m_pBlocks)
        {
            m_pBlocks->Destroy();
            m_pBlocks = nullptr;
        }

        if (nullptr != m_pChunks)
        {
            m_pChunks->Destroy();
            m_pChunks = nullptr;
        }

        if (m_bIntAlloc)
        {
            free(this);
        }
    }

    CBuffer<CLock> *NewBuffer()
    {
        void *ptr = nullptr;
        BufNode *pBufNode = nullptr;

        if (m_lstBuffer.IsEmpty())
        {
            if (nullptr == m_pChunks)
                return nullptr;

            ptr = m_pChunks->Alloc(sizeof(BufNode));
        }
        else
        {
            ptr = (void *)m_lstBuffer.PopFront();
        }

        if (nullptr != ptr)
        {
            memset(ptr, 0, sizeof(BufNode));
            pBufNode = (BufNode *)m_lstBuffer.NewNode(ptr);
        }

        if (nullptr != pBufNode)
        {
            pBufNode->SetBufMgr(this);
            // pBufNode->SetSocket(ifd);
        }

        return (CBuffer<CLock> *)pBufNode;
    }

    // CBuffer不用后，必须调用DeleteBuffer，以释放CBuffer占用的BlockNode
    bool DeleteBuffer(CBuffer<CLock> *pBuffer)
    {
        if (nullptr == pBuffer)
            return false;

        // 释放CBuffer占用的BlockNode
        pBuffer->Destroy();

        return m_lstBuffer.PushBack((BufNode *)pBuffer);
    }

    BlockNode *GetBlock()
    {
        return (nullptr != m_pBlocks) ? m_pBlocks->GetBlock() : nullptr;
    }

    bool FreeBlock(BlockNode *pNode)
    {
        return (nullptr != m_pBlocks) ? m_pBlocks->FreeBlock(pNode) : false;
    }

private:
    CBufLst m_lstBuffer;            // 已不使用的CBuffer列表
    CBufBlockMgr<CLock> *m_pBlocks; // 小块管理
    CBufChunkMgr<CLock> *m_pChunks; // 大块管理
    bool m_bIntAlloc;               // 是否为内部分配内存
};

// #include <stddef.h>
// #include "Singleton.h"
// #include "BufBlock.h"

// class CBufBlockMgr;
// class CBufChunkMgr;

// class CBufMgr : public CSingleton<CBufMgr>
// {
//     friend class CSingleton;

// public:
//     ~CBufMgr();
//     void operator delete(void *ptr);

//     CBufMgr(const CBufMgr &rhs) = delete;
//     CBufMgr &operator=(const CBufMgr &rhs) = delete;
//     CBufMgr &operator=(CBufMgr &&rhs) = delete;

// public:
//     bool Init();
//     void Destroy();
//     BufBlockNode *GetBlock();
//     bool FreeBlock(BufBlockNode *pNode);

// private:
//     CBufMgr();
//     void *operator new(size_t sz);

// private:
//     CBufChunkMgr *m_pChunks;
//     CBufBlockMgr *m_pBlocks;
// };
